#pragma once

#include <signal.h>
#include <unistd.h>
#include <poll.h>

#include <cstring>

#include <string>
#include <vector>

#include "socket.hpp"
#include "log.hpp"
extern Log log;

constexpr uint16_t default_port = 8081;

constexpr size_t fd_max_nums = 128;

constexpr uint16_t default_fd = -1;
constexpr uint16_t non_event = 0;

int Receive(int fd)
{
    char buffer[1024] = { 0 };
    ssize_t n = read(fd, buffer, sizeof(buffer) - 1);
    if (n > 0)
    {
        buffer[n - 1] = '\0';
        std::cout << "fd " << fd << " get message: " << buffer << std::endl;
    }
    else if (n == 0)
    {
        log(Info, "client quit, read done");
        close(fd);
    }
    else
        log(Warning, "read error, fd = %d, n = %d, errno: %d, error string: %s", fd, n, errno, strerror(errno));
    return n;
}

class Poll_Server
{
public:
    Poll_Server(uint16_t port = default_port)
        : _port(port)
    {
        for (size_t i = 0; i < fd_max_nums; ++i)
        {
            _event_fds[i].fd = default_fd;
            _event_fds[i].events = non_event;
            _event_fds[i].revents = non_event;
        }
    }

    bool init()
    {
#ifdef __TEST__DEBUG__
        signal(SIGCHLD, SIG_IGN);
#else
        log.change_method(Class);
        daemon(1, 0);
#endif
        _listen_socket.Create(SOCK_STREAM);
        _listen_socket.Bind(_port);
        _listen_socket.Listen();
    }

    void start()
    {
        _event_fds[0] = { _listen_socket.socket_fd(), POLLIN, non_event };
        while (true)
        { 
            int n = poll(_event_fds, fd_max_nums, 1000);
            switch (n)
            {
            case 0:
                std::cout << "time out" << std::endl;
                break;
            case -1:
                std::cerr << "poll error" << std::endl;
                break;
            default:
                Dispatcher();
                break;
            }
        }
    }

    void Dispatcher()
    {
        for (size_t i = 0; i < fd_max_nums; ++i)
        {
            if (_event_fds[i].fd != default_fd && _event_fds[i].revents & POLLIN)
            {
                // 链接fd
                if (_event_fds[i].fd == _listen_socket.socket_fd())
                    Accept();
                else
                {
                    // 处理链接fd
                    if (Receive(_event_fds[i].fd) == 0)
                    {
                        _event_fds[i].fd = default_fd;
                        _event_fds[i].events = non_event;
                        _event_fds[i].revents = non_event;
                    }
                }
            }
        }
    }
private:
    void Accept()
    {
        std::string client_ip;
        uint16_t client_port;
        int fd = _listen_socket.Accept(client_ip, client_port);
        // 添加链接fd
        bool flag = false;
        for (size_t i = 0; i < fd_max_nums; ++i)
        {
            if (_event_fds[i].fd == default_fd)
            {
                _event_fds[i].fd = fd;
                _event_fds[i].events = POLLIN;
                _event_fds[i].revents = non_event;
                flag = true;
                break;
            }
        }
        if (!flag)
        {
            log(Warning, "server is full, close %d now", fd);
            close(fd);
        }
#ifdef __TEST__DEBUG__
        else
        {
            std::cout << "online fd list: ";
            for (size_t i = 0; i < fd_max_nums; ++i)
            {
                if (_event_fds[i].fd != default_fd)
                    std::cout << _event_fds[i].fd << ' ';
            }
            std::cout << std::endl;
        }
#endif
    }
private:
    Socket _listen_socket;
    uint16_t _port;
    struct pollfd _event_fds[fd_max_nums];
};